package com.fast.linkbeanadmin.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fast.linkbeanadmin.exception.BusinessException;
import com.fast.linkbeanadmin.mapper.SysAuthorityMapper;
import com.fast.linkbeanadmin.mapper.SysUserMapper;
import com.fast.linkbeanadmin.pojo.dto.SecurityUserDTO;
import com.fast.linkbeanadmin.pojo.entity.SysAuthorityDO;
import com.fast.linkbeanadmin.pojo.entity.SysUserDO;
import com.fast.linkbeanadmin.pojo.vo.UserRouteVO;
import com.fast.linkbeanadmin.pojo.vo.UserVO;
import com.fast.linkbeanadmin.pojo.vo.route.UserRouteMetaVO;
import com.fast.linkbeanadmin.service.SysUserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author ruan cai yuan
 * @version 1.0
 * @fileName com.fast.linkbeanadmin.service.impl.SysUserServiceImpl
 * @description: 针对表【sys_user(用户信息表)】的数据库操作Service实现
 * @since 2024/7/21 下午4:52
 */
@Service
@Slf4j
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUserDO> implements SysUserService {
    @Resource
    private SysUserMapper userMapper;
    @Resource
    private SysAuthorityMapper authorityMapper;

    /**
     * 根据用户的ID查询用户
     *
     * @param id 用户ID
     */
    @Override
    public UserVO queryById(Long id) {
        SysUserDO userDO = userMapper.selectById(id);
        return Convert.convert(UserVO.class, userDO);
    }

    /**
     * 根据用户的账号查询用户
     *
     * @param username 用户账号
     */
    @Override
    public UserDetails loadUserByUsername(String username) {
        LambdaQueryWrapper<SysUserDO> lqw = Wrappers.<SysUserDO>lambdaQuery().eq(SysUserDO::getUserName, username);
        SysUserDO userDO = getOne(lqw);
        if (ObjUtil.isEmpty(userDO)) {
            log.error("账号: {} 信息不存在系统中", username);
            throw new BusinessException("账号信息不存在");
        }
        // 查询用户权限信息
        List<SysAuthorityDO> userAuthorities = authorityMapper.queryUserAuthorities(userDO.getId());
        Set<String> backAuthorizedUris = toBackAuthorizedUris(userAuthorities);
        List<UserRouteVO> userRoutes = toUserRoutes(userAuthorities);

        SecurityUserDTO dto = new SecurityUserDTO();
        dto.setUserDO(userDO);
        dto.setBackAuthorizedUris(backAuthorizedUris);
        dto.setUserRoutes(userRoutes);
        return dto;
    }

    /**
     * 转换为后端校验的请求路径（相对路径）：backAuthorizedUris
     */
    private Set<String> toBackAuthorizedUris(List<SysAuthorityDO> userAuthorities) {
        if (CollUtil.isEmpty(userAuthorities)) {
            return Collections.emptySet();
        }
        Set<String> set = new HashSet<>();
        for (SysAuthorityDO userAuthority : userAuthorities) {
            set.addAll(Arrays.asList(userAuthority.getRelateBackUris().split(StringPool.COMMA)));
            List<SysAuthorityDO> children = userAuthority.getChildren();
            if (children != null && !children.isEmpty()) {
                for (SysAuthorityDO child : children) {
                    set.addAll(Arrays.asList(child.getRelateBackUris().split(StringPool.COMMA)));
                }
            }
        }
        return set;
    }

    /**
     * 转换为前端加载菜单的路由
     */
    private List<UserRouteVO> toUserRoutes(List<SysAuthorityDO> userAuthorities) {
        if (CollUtil.isEmpty(userAuthorities)) {
            return Collections.emptyList();
        }
        return userAuthorities.stream()
                .map(userAuthority -> {
                    UserRouteVO userRouteVo = Convert.convert(UserRouteVO.class, userAuthority);
                    UserRouteMetaVO userRouteMetaVo = Convert.convert(UserRouteMetaVO.class, userAuthority);
                    userRouteVo.setMeta(userRouteMetaVo);
                    return userRouteVo;
                }).collect(Collectors.toList());
    }
}




